#ifndef resource_manager_h
#define resource_manager_h

#include "singleton.h"
#include "logger.h"
#include <string>
#include <map>
using namespace std;

class ResourceLoader;

class ResourceManager: public Singleton<ResourceManager> {
  friend class Singleton<ResourceManager>;

  public:
    /**
      * Initializes the resource manager.
      * @rootpath Root path where to find the resources
      * @loadAtStart if true, loads all the indexed resources now
      * @sa loadAll default is true
      */
    void initialize (const string& rootpath, bool loadAtStart = true);

    /**
      * Get the specified resource. If it is not loaded it is loaded.
      * Else it is simply returned.
      */
    inline void* get (const string& key);

    /**
      * Loads all the indexed resources now.
      */
    inline void loadAll ();

    /**
      * Unloads all the loaded resources now.
      * This is done automatically at releasing the singleton.
      */
    inline void unloadAll ();

    /**
      * Unloads the specific resource.
      * This method is typically used for freeing memory
      * occupied by big resources.
      * @param key resource key
      */
    void unload (const string& key);

  private:
    ResourceManager ();
    ~ResourceManager ();

    /**
      * Loads the specific resource. If a resource was already loaded
      * it is unloaded first.
      * Note that you'll need to cast the returned data.
      * @param key resource key
      */
    void* load (const string& key);

    /**
      * Given a path, extract the extension of the file.
      */
    inline static string getExtension (const string& path);

    /**
      * Initializes the map associating each supported extension with a loader.
      */
    void initLoadersMap();

  private:
    /**
      * Associates a loader with an extension.
      * Example : png -> ImageLoader
      * Initialized in the constructor, in the cpp file.
      */
    map<string, ResourceLoader*> ext2loader;

    /**
      * Index of the available resources.
      */
    map<string,string> resourceIndex;

    /**
      * Resource data.
      */
    map<string, void*> resources;
};

string ResourceManager::
getExtension (const string& path) {
  int size = path.size();
  return path.substr(size - 3, 3);
}

void ResourceManager::
loadAll () {
  map<string, string>::iterator itr;
  for (itr = resourceIndex.begin(); itr != resourceIndex.end(); ++itr) {
    string key = (*itr).first;
    load(key);
  }
}

void ResourceManager::
unloadAll () {
  map<string, string>::iterator itr;
  for (itr = resourceIndex.begin(); itr != resourceIndex.end(); ++itr) {
    string key = (*itr).first;
    unload(key);
  }
}

void* ResourceManager::
get (const string& key) {
  map<string, void*>::iterator itr = resources.find(key);
  // The resource is already loaded, return it.
  if (itr != resources.end()) {
    return (*itr).second;
  }
  // The resource is not loaded, load it and return it.
  return load(key);
}

#endif

